package com.xqboss.apps.service.consumer;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.domain.consumer.ConsumerTeamGainRule;
import com.xqboss.apps.domain.consumer.ConsumerTeamUpgradePlan;
import com.xqboss.apps.dto.consumer.ConsumerTeamUpgradePlanDto;
import com.xqboss.apps.dto.team.ConsumerTeamUpgradeAmplifyDto;
import com.xqboss.apps.enums.consumer.ConsumerTeamUpgradePlanTypeEnum;
import com.xqboss.apps.enums.user.UserWalletEnum;
import com.xqboss.apps.mapper.consumer.ConsumerTeamUpgradePlanMapper;
import com.xqboss.apps.service.punch.PunchUserRecordService;
import com.xqboss.apps.service.sys.ConfigService;
import com.xqboss.apps.service.user.SysUserNftService;
import com.xqboss.apps.service.user.SysUserWalletService;
import com.xqboss.apps.service.user.UserAssetWrenchService;
import com.xqboss.apps.vo.consumer.ConsumerTeamVo;
import com.xqboss.apps.vo.consumer.TeamCommonUpgradesVo;
import com.xqboss.apps.vo.consumer.TeamOrdinaryInfoVo;
import com.xqboss.apps.vo.consumer.TeamUpgradeConditionVo;
import com.xqboss.apps.vo.sys.TeamProfileVo;
import com.xqboss.apps.vo.team.ConsumerTeamUpgradeAmplifyVo;
import com.xqboss.common.core.domain.R;
import com.xqboss.common.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 队伍升级方案(ConsumerTeamUpgradePlan)表服务接口
 *
 * @author makejava
 * @since 2023-12-15 14:27:10
 */
@Service
public class ConsumerTeamUpgradePlanService extends ServiceImpl<ConsumerTeamUpgradePlanMapper, ConsumerTeamUpgradePlan> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private ConsumerTeamGainRuleService consumerTeamGainRuleService;
    @Autowired
    private SysUserWalletService userWalletService;
    @Autowired
    private UserAssetWrenchService userAssetWrenchService;
    @Autowired
    private SysUserNftService sysUserNftService;//用户藏品
    @Autowired
    private ConsumerTeamGiveRecordService consumerTeamGiveRecordService;//队伍转增记录
    @Autowired
    private PunchUserRecordService punchUserRecordService;//用户-打卡记录
    @Autowired
    private ConsumerTeamMemberService consumerTeamMemberService;//队伍成员

    /**
     * 队伍升级方案
     *
     * @return String
     */
    public ConsumerTeamUpgradeAmplifyVo planConf() {
        ConsumerTeamUpgradeAmplifyVo amplifyVo = new ConsumerTeamUpgradeAmplifyVo();
        TeamProfileVo teamProfile = configService.getTeamProfile();
        BeanUtil.copyProperties(teamProfile, amplifyVo);
        //队伍升级-增益规则列表
        List<ConsumerTeamGainRule> rules = consumerTeamGainRuleService.list();
        amplifyVo.setTeamGainRule(rules);
        //队伍升级-方案
        List<ConsumerTeamUpgradePlan> plans = this.list();
        amplifyVo.setTeamUpgradePlan(plans);
        return amplifyVo;
    }

    /**
     * 队伍升级方案详情
     *
     * @return 详情
     */
    public R<List<ConsumerTeamUpgradePlanDto>> planInfo() {
        return null;
    }


    /**
     * 获取所有升级方案配置
     *
     * @return List<ConsumerTeamUpgradePlan>
     */
    public List<ConsumerTeamUpgradePlan> getConsumerTeamUpgradePlans() {
        List<ConsumerTeamUpgradePlan> upgradePlans = this.list();
        if (upgradePlans.isEmpty()) {
            throw new ServiceException("未找到升级方案，请检查配置!");
        }
        return upgradePlans;
    }

    /**
     * 获取当前用户的热豆和扳手余额
     *
     * @param userId 用户id
     * @return  [热豆余额，扳手余额]
     */
    public BigDecimal[] getHotBeansAndWrenchBalance(Long userId){
        //获取热豆余额
        BigDecimal hotBeansBalance = userWalletService.getWallet(userId, UserWalletEnum.INTEGRAL).getAmount();
        //获取扳手余额
        BigDecimal WrenchBalance = userAssetWrenchService.getWrench(userId).getAmount();

        return new BigDecimal[]{hotBeansBalance,WrenchBalance};
    }

    /**
     * 是否支持材料升级
     *
     * @param upgradePlans 升级方案
     * @param currentRank 当前队伍等级
     * @param balance [热豆余额，扳手余额]
     * @param userId 用户id
     * @param vo 材料升级条件
     */
    public void isMaterialUpgrade(List<ConsumerTeamUpgradePlan> upgradePlans, Integer currentRank, BigDecimal[] balance,Long userId, TeamUpgradeConditionVo vo) {
        //材料升级是否开启
        boolean isOpen = isOpen(upgradePlans,ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_ONE);
        //开启了材料升级，验证有无藏品、热豆和扳手是否充足
        if (isOpen) {
            //转map
            Map<ConsumerTeamUpgradePlanTypeEnum, ConsumerTeamUpgradePlan> upgradePlanMap = getConsumerTeamUpgradePlanMap(upgradePlans);
            //验证是否有藏品
            // 获取藏品/装备id
            Long nftId = upgradePlanMap.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_ONE).getNftId();
            if (nftId==null) {
                vo.setIsMaterialUpgrade(Boolean.FALSE);
                vo.setUnMaterialUpgradeReason("藏品/宝盒/装备id不存在，请检查升级方案配置！");
                return ;
            }
            // 藏品/宝盒/装备数量
            long nftNumberCounts = this.sysUserNftService.getNftNumberCounts(nftId, userId);
            if (nftNumberCounts==0) {
                vo.setIsMaterialUpgrade(Boolean.FALSE);
                vo.setUnMaterialUpgradeReason("无对应藏品~");
                return ;
            }
            //获取材料升级需要消耗的热豆数量 和 扳手数量
            BigDecimal consumeHotBeans = countConsumeHotBeansOrWrenchs(currentRank,upgradePlanMap.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_ONE));//材料升级二级热豆消耗
            boolean isHotBeans = balance[0].compareTo(consumeHotBeans)>=0;
            if (!isHotBeans) {
                vo.setIsMaterialUpgrade(Boolean.FALSE);
                vo.setUnMaterialUpgradeReason("热豆余额不足~");
                return;
            }
            BigDecimal consumeWrench = countConsumeHotBeansOrWrenchs(currentRank,upgradePlanMap.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_TWO));//材料升级二级扳手消耗
            boolean isWrench = balance[1].compareTo(consumeWrench)>=0;
            if (!isWrench) {
                vo.setIsMaterialUpgrade(Boolean.FALSE);
                vo.setUnMaterialUpgradeReason("扳手余额不足~");
            }
        }else{
            vo.setIsMaterialUpgrade(Boolean.FALSE);
            vo.setUnMaterialUpgradeReason("未开启材料升级~");
        }
    }

    /**
     * 是否开启升级按钮（材料 或 普通）
     *
     * @param upgradePlans 升级方案
     * @param typeEnum 材料 或 普通
     * @return true开启
     */
    public boolean isOpen(List<ConsumerTeamUpgradePlan> upgradePlans,ConsumerTeamUpgradePlanTypeEnum typeEnum) {
        return upgradePlans.stream().filter(p -> p.getType() == typeEnum).anyMatch(p -> p.getIsOpen() == 1);
    }

    /**
     * 是否支持普通升级
     *
     * @param upgradePlans 升级方案
     * @param team 当前队伍
     * @param balance [热豆余额，扳手余额]
     * @param vo 普通升级条件
     */
    public void isOrdinaryUpgrade(List<ConsumerTeamUpgradePlan> upgradePlans, ConsumerTeamVo team, BigDecimal[] balance, TeamUpgradeConditionVo vo) {
        //普通升级是否开启
        boolean isOpen = isOpen(upgradePlans,ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_THREE);
        //开启了普通升级，验证热豆和扳手是否充足
        if (isOpen) {
            Integer currentRank = team.getRank();
            //转map
            Map<ConsumerTeamUpgradePlanTypeEnum, ConsumerTeamUpgradePlan> upgradePlanMap = getConsumerTeamUpgradePlanMap(upgradePlans);
            //获取队伍普通升级条件
            List<TeamOrdinaryInfoVo> info = getTeamOrdinaryInfoVos(upgradePlanMap, team.getId(), team.getRank(), team.getMemberCount(), team.getMaxNumber());
            Map<Integer, TeamOrdinaryInfoVo> voMap = info.stream().collect(Collectors.toMap(TeamOrdinaryInfoVo::getType, Function.identity()));
            if (!voMap.get(TeamOrdinaryInfoVo.Type.TEAM_NUMBER).getIsOk()) {
                vo.setIsOrdinaryUpgrade(Boolean.FALSE);
                vo.setUnOrdinaryUpgradeReason("队伍人数未达标~");
                return;
            }
            if (!voMap.get(TeamOrdinaryInfoVo.Type.GIFT_NUMBER).getIsOk()) {
                vo.setIsOrdinaryUpgrade(Boolean.FALSE);
                vo.setUnOrdinaryUpgradeReason("互送礼物未达标~");
                return;
            }
            if (!voMap.get(TeamOrdinaryInfoVo.Type.PUNCH_NUMBER).getIsOk()) {
                vo.setIsOrdinaryUpgrade(Boolean.FALSE);
                vo.setUnOrdinaryUpgradeReason("累计打卡未达标~");
                return;
            }
            if (!voMap.get(TeamOrdinaryInfoVo.Type.REAL_NAME).getIsOk()) {
                vo.setIsOrdinaryUpgrade(Boolean.FALSE);
                vo.setUnOrdinaryUpgradeReason("队伍实名未达标~");
                return;
            }
            //获取普通升级需要消耗的热豆数量 和 扳手数量
            BigDecimal consumeHotBeans = countConsumeHotBeansOrWrenchs(currentRank,upgradePlanMap.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_FIVE));//普通升级二级热豆消耗
            boolean isHotBeans = balance[0].compareTo(consumeHotBeans)>=0;
            if (!isHotBeans) {
                vo.setIsOrdinaryUpgrade(Boolean.FALSE);
                vo.setUnOrdinaryUpgradeReason("热豆余额不足~");
                return;
            }
            BigDecimal consumeWrench = countConsumeHotBeansOrWrenchs(currentRank,upgradePlanMap.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_SEX));//普通升级二级扳手消耗
            boolean isWrench = balance[1].compareTo(consumeWrench)>=0;
            if (!isWrench) {
                vo.setIsOrdinaryUpgrade(Boolean.FALSE);
                vo.setUnOrdinaryUpgradeReason("扳手余额不足~");
            }
        }else{
            vo.setIsOrdinaryUpgrade(Boolean.FALSE);
            vo.setUnOrdinaryUpgradeReason("未开启普通升级~");
        }
    }

    /**
     * 获取队伍普通升级条件
     *
     * @param map 升级方案
     * @param teamId 队伍id
     * @param currentRank 当前队伍等级
     * @param hasNumber 当前队伍已有人数
     * @param currentNumber 当前队伍人数上限
     * @return List
     */
    public List<TeamOrdinaryInfoVo> getTeamOrdinaryInfoVos(Map<ConsumerTeamUpgradePlanTypeEnum, ConsumerTeamUpgradePlan> map,
                                                           Long teamId,
                                                           Integer currentRank,
                                                           Integer hasNumber,
                                                           Integer currentNumber) {

        // 队伍人数
        int a1 = hasNumber;
        int a2 = currentNumber;

        // 互送礼物
        int b1 = this.consumerTeamGiveRecordService.countGift(teamId).intValue();
        int b2 = getGiftOrPunchNumberTotal(currentRank,map.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_FOUR));

        // 累计打卡
        int c1 = this.punchUserRecordService.countTeamTotalPunch(teamId).intValue();
        int c2 = getGiftOrPunchNumberTotal(currentRank,map.get(ConsumerTeamUpgradePlanTypeEnum.CONSUME_TYPE_THREE));

        // 队伍实名
        int d1 = this.consumerTeamMemberService.getBaseMapper().countTeamRealName(teamId);
        int d2 = currentNumber;

        return CollectionUtil.newArrayList(
                // 队伍人数
                TeamOrdinaryInfoVo.builder().type(TeamOrdinaryInfoVo.Type.TEAM_NUMBER).isOk(a1>=a2).numerator(a1).denominator(a2).build(),
                // 互送礼物
                TeamOrdinaryInfoVo.builder().type(TeamOrdinaryInfoVo.Type.GIFT_NUMBER).isOk(b1>=b2).numerator(b1).denominator(b2).build(),
                // 累计打卡
                TeamOrdinaryInfoVo.builder().type(TeamOrdinaryInfoVo.Type.PUNCH_NUMBER).isOk(c1>=c2).numerator(c1).denominator(c2).build(),
                // 队伍实名
                TeamOrdinaryInfoVo.builder().type(TeamOrdinaryInfoVo.Type.REAL_NAME).isOk(d1>=d2).numerator(d1).denominator(d2).build()
        );
    }

    /**
     * 按升级方案配置转为map
     *
     * @param upgradePlans 升级方案
     * @return map
     */
    public Map<ConsumerTeamUpgradePlanTypeEnum, ConsumerTeamUpgradePlan> getConsumerTeamUpgradePlanMap(List<ConsumerTeamUpgradePlan> upgradePlans) {
        return upgradePlans.stream().collect(Collectors.toMap(ConsumerTeamUpgradePlan::getType, Function.identity()));
    }

    /**
     * 获取 当前队伍等级 需要满足的最高 互送礼物 或 累计打卡 数量
     *
     * @param currentRank 当前的队伍等级（未升级前）
     * @param plan 升级方案（互送礼物 或 累计打卡）
     * @return 最高 互送礼物 或 累计打卡 数量
     */
    public int getGiftOrPunchNumberTotal(int currentRank, ConsumerTeamUpgradePlan plan) {
        Integer consume = plan.getConsume();
        if (currentRank==1) {
            return consume;
        }
        int factor = plan.getFactor().intValue();
        return consume+(currentRank-1)*factor;
    }

    /**
     * 计算需要消耗的热豆或扳手数量
     *
     * @param currentRank 当前的队伍等级（未升级前）
     * @param plan 升级方案（材料或普通升级的热豆或扳手）
     * @return 需要消耗的热豆或扳手数量
     */
    public BigDecimal countConsumeHotBeansOrWrenchs(int currentRank, ConsumerTeamUpgradePlan plan){
        DecimalFormat df = new DecimalFormat("#.00");//保留两位有效值
        Integer consume = plan.getConsume();
        if (currentRank ==1) {
            return new BigDecimal(df.format(consume));
        }
        BigDecimal factor = plan.getFactor();
        BigDecimal bigDecimal = new BigDecimal(consume * Math.pow(factor.doubleValue(), currentRank - 1));
        return new BigDecimal(df.format(bigDecimal));
    }

    /**
     * 编辑队伍升级规则
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean planEdit(ConsumerTeamUpgradeAmplifyDto params) {
        TeamProfileVo profileVo = BeanUtil.copyProperties(params, TeamProfileVo.class);
        //编辑队伍升级配置
        configService.updateTeamConfig(profileVo);
        //编辑增益规则
        try {
            boolean rule = consumerTeamGainRuleService.saveOrUpdateBatch(params.getTeamGainRule());
            if (!rule) {
                throw new ServiceException("编辑队伍升级规则失败");
            }
        } catch (Exception e) {
            throw new ServiceException("打卡次数重复");
        }
        //编辑队伍升级方案
        boolean plan = this.saveOrUpdateBatch(params.getTeamUpgradePlan());
        if (!plan) {
            throw new ServiceException("编辑升级方案失败");
        }
        return true;
    }
}

